package com.zombie.logic.object;

import java.util.ArrayList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.zombie.ResourceManager;
import com.zombie.effect.DroppedShellEffect;
import com.zombie.input.Input;
import com.zombie.logic.Reload;
import com.zombie.logic.core.ZombieWorld;
import com.zombie.logic.enums.AnimationType;
import com.zombie.logic.enums.ItemType;
import com.zombie.logic.enums.ObjectType;
import com.zombie.logic.item.Ammo;
import com.zombie.logic.item.Explosive;
import com.zombie.logic.item.Heal;
import com.zombie.logic.item.Item;
import com.zombie.logic.item.Weapon;
import com.zombie.logic.item.WeaponType;
import com.zombie.state.GameState;
import com.zombie.util.ThreadPoolManager;
import com.zombie.util.Utils;

public class Player extends LiveObject {

	public int shots;
	public int hits;
	public int kills;
	public int money;
	public int skillPoints = 1111110;
	public ArrayList<Weapon> weapons = new ArrayList<Weapon>();
	public ArrayList<Item> items = new ArrayList<Item>();
	public int itemPosition = -1;

	int calculatedMaxHp = 0;
	float calculatedVelocity = 0;
	Vector2 shotPosOneHanded, shotPosTwoHanded;
	Vector2 shotPosition = new Vector2();
	
	public Player(float x, float y){
		super(x,y);
		type = ObjectType.PLAYER;
		image = "zombie1";
		size = new Vector2(28,28);
		pickup(Weapon.getWeaponById(0).clone());
		weapon = weapons.get(0);
		super.setVelocity(1.0f);
		createBody();
		shotPosOneHanded = new Vector2(28,11);
		shotPosTwoHanded = new Vector2(36,0);
	}

	public void upAgility(){
		if (skillPoints < 1)
			return;
		getStat().agility+=1;
		setVelocity(super.getVelocity() + getStat().agility/25f*1.4f);
		getStat().evasion=getStat().agility*0.1f*1.5f; // 1f = 100%  0.1 = 10% 0.01 = 1% 
		if (getStat().evasion > 0.5f)
			getStat().evasion = 0.5f;
		skillPoints--;
		
		System.out.println("velocity " + getVelocity());
	}
	
	public void upStrength(){
		if (skillPoints < 1)
			return;
		getStat().strength+=1;
		getStat().defence=getStat().strength/2-5;
		skillPoints--;
	}	
	
	public void upEndurance(){
		if (skillPoints < 1)
			return;
		getStat().endurance+=1;
		setMaxHp((int) (super.getMaxHp() + (getStat().endurance*getStat().endurance)/10) - 10);
		skillPoints--;
	}		
	
	public int getMaxHp(){
		if (calculatedMaxHp == 0)
			return super.getMaxHp();
		return calculatedMaxHp;
	}

	public void setMaxHp(int newHp){
		calculatedMaxHp = newHp;
	}
	
	public float getVelocity(){
		if (calculatedVelocity == 0)
			return super.getVelocity();
		return calculatedVelocity;
	}

	public void setVelocity(float velocity){
		calculatedVelocity = velocity;
	}
	
	@Override
	public void update(float delta) {
		super.update(delta);
		if (animation == AnimationType.DIE)
			return;
		animation = AnimationType.STAND;

		if (Input.isPressed(Keys.W))
			body.applyForceToCenter(0, getVelocity());
		else if (Input.isPressed(Keys.S))
			body.applyForceToCenter(0, -getVelocity());
		if (Input.isPressed(Keys.A))
			body.applyForceToCenter(-getVelocity(),0);
		else if (Input.isPressed(Keys.D))
			body.applyForceToCenter(getVelocity(),0);
		if (Input.isPressed(Keys.W)||Input.isPressed(Keys.A)||Input.isPressed(Keys.S)||Input.isPressed(Keys.D)){
			animation = AnimationType.MOVE;
			if (lastStep+stepTime < GameState.time){
				stepSound();
			}
		}
		moveTick+=delta;
		if (moveTick >= 1000)
			moveTick = 0;
		float rads = MathUtils.atan2((GameState.getInstance().offsetY-Gdx.graphics.getHeight()/2+Input.mouseY)-position.y, (GameState.getInstance().offsetX-Gdx.graphics.getWidth()/2+Input.mouseX)-position.x);
		angle = 360 - rads* MathUtils.radDeg;
		if (angle > 360)
			angle -=360;
		if (angle < 0)
			angle +=360;
		if (Input.isMousePressed(Buttons.LEFT))
			hit();		
	}

	public int getExp() {
		return getStat().exp;
	}

	public void setExp(int exp) {
		getStat().exp = exp;
		checkForLevel();
	}

	private void checkForLevel() {
		int needExp = 100+100*getLevel() + getLevel()*getLevel()*10;
		if (getStat().exp > needExp)
			levelUp();
	}

	private void levelUp() {
		getStat().level++;
		skillPoints+= 2 + getLevel()/2;
//		LevelUpEffect eff = new LevelUpEffect();
//		eff.setFullLifeTime(3000);
//		GameState.addEffect(eff);
//		if (getLevel() == 1){
//			TextEffect eff2 = new TextEffect();
//			eff2.text = "Level up! To raise stats press C";
//			eff2.position = new Vector2f(300,260);
//			GameState.addEffect(eff2);
//		}
	}

	private void hit() {
//		if (GameState.time < lastHit+weapon.hitTime || weapon.ammo <=0)
//			return;
//		if (reload != null)
//			return;
//		if (weapon.ammo > 0)
//			weapon.ammo--;
//		if (weapon.ammo == 0 && weapon.totalAmmo != 0)
//			reload();
//		
		ResourceManager.getSound(weapon.shootSound).play();
		lastHit = GameState.time;		
		shots++;
		
		if (!weapon.twoHanded)
			shotPosition.set(shotPosOneHanded);
		else
			shotPosition.set(shotPosTwoHanded);
		
		shotPosition.x *=MathUtils.cos(MathUtils.degRad*angle);
		shotPosition.y *=MathUtils.sin(MathUtils.degRad*angle);			
		float startX = position.x + shotPosition.x;
		float startY = position.y + shotPosition.y;	
		
//		ConfigurableEmitter emi = ResourceManager.getParticleEmitter(weapon.particle_shot2).duplicate();
//		emi.setPosition(startX,startY,false);
//		emi.angularOffset.setValue((float) angle+90);
//		GameState.particleSystem.addEmitter(emi);
//		emi = ResourceManager.getParticleEmitter(weapon.particle_shot).duplicate();
//		emi.setPosition(startX,startY,false);
//		emi.angularOffset.setValue((float) angle+90);
//		GameState.particleSystem.addEmitter(emi);
//		
//		if (weapon.weaponType == WeaponType.ROCKET){
//			ExplosiveObject obj = new ExplosiveObject(pos.x,pos.y,(Explosive)Item.getItemById(weapon.bullet.explosiveId));
//			obj.angle = angle;
//			obj.imageAngle = (float) angle+90;
//			obj.owner = this;
//			GameState.addObject(obj);
//			ConfigurableEmitter smoke = ResourceManager.getParticleEmitter("rocket_smoke").duplicate();
//			smoke.setPosition(startX,startY);
//			GameState.particleSystem.addEmitter(smoke);
//			RocketTracerEffect eff = new RocketTracerEffect();
//			eff.setOwner(obj);
//			eff.emitter = smoke;
//			GameState.addEffect(eff);
//			return;
//		}
		int count = 1;
		if (weapon.weaponType == WeaponType.SHOTGUN)
			count = 5+Utils.rnd.nextInt(2);
		
		for(int i = 0; i < count;i++){
			Bullet b = new Bullet(startX,startY,this,angle+ (-weapon.rndAngle/2+Utils.rnd.nextInt((int) (weapon.rndAngle+1))));
			b.setParams(weapon);
			ZombieWorld.addObject(b);
		}

		DroppedShellEffect shellEffect = new DroppedShellEffect();
		shellEffect.angle = 360*Utils.rnd.nextFloat();
		shellEffect.position.set(position.x+Utils.randomInt(-4, 8),position.y+Utils.randomInt(-4, 8));
		shellEffect.setFullLifeTime(1000L);
		ZombieWorld.addEffect(shellEffect);
	}
	
	public void reload() {
		if (isDead())
			return;
		if (weapon.ammo == weapon.maxAmmo)
			return;
		if (reload != null && !reload.isDone())
			return;
		if (weapon.totalAmmo == 0)
			return;
		reload = ThreadPoolManager.getInstance().scheduleGeneral(new Reload(this), weapon.reloadTime);
		ResourceManager.getSound(weapon.clipoutSound).play();
	}

	int moveTick = 0;
	@Override
	public void draw(SpriteBatch batch, ShapeRenderer shapeBatch) {
		if (animation == AnimationType.MOVE){
			Animation a = ResourceManager.getAnimation(image+"_move");
			TextureRegion region = a.getKeyFrame(GameState.time);
			batch.draw(region, position.x-16, position.y-16, 16, 16, 32, 32, 1, 1, angle);
		}else if (animation == AnimationType.STAND){
			Animation a = ResourceManager.getAnimation(image+"_stand");
			TextureRegion region = a.getKeyFrame(GameState.time);
			batch.draw(region, position.x-16, position.y-16, 16, 16, 32, 32, 1, 1, angle);		
		}
//		if (animation == AnimationType.STAND)
//			ResourceManager.getImage(image+"_stand").draw(pos.x-wh.x/2, pos.y-wh.y/2, 32, 32);
//		else if (animation == AnimationType.MOVE)
//			ResourceManager.getAnimation(image+"_move").draw(pos.x-wh.x/2, pos.y-wh.y/2, 32, 32);
//		else if (animation == AnimationType.DIE)
//			ResourceManager.getAnimation(image+"_die").draw(pos.x-wh.x/2, pos.y-wh.y/2, 32, 32);
//		GameState.sprite.setPosition(position.x, position.y);
//		GameState.sprite.setScale(size.x/GameState.sprite.getWidth());
//		GameState.sprite.setRotation(angle);
//		GameState.sprite.draw(batch);
//		g.rotate(pos.x, pos.y, (float) angle);
//		if (animation == AnimationType.STAND)
//			ResourceManager.getImage(image+"_stand").draw(pos.x-wh.x/2, pos.y-wh.y/2, 32, 32);
//		else if (animation == AnimationType.MOVE)
//			ResourceManager.getAnimation(image+"_move").draw(pos.x-wh.x/2, pos.y-wh.y/2, 32, 32);
//		else if (animation == AnimationType.DIE)
//			ResourceManager.getAnimation(image+"_die").draw(pos.x-wh.x/2, pos.y-wh.y/2, 32, 32);
//		g.rotate(pos.x, pos.y, (float) -angle);
//		int tick = moveTick/330;
//		if (animation != AnimationType.MOVE)
//			tick = 0;
//		g.rotate(pos.x, pos.y, (float) angle);
//		g.setColor(Color.green);
//		g.fillOval(pos.x-8, pos.y-10, 16, 20);
//		g.setColor(Color.gray);
//		g.fillOval(pos.x-5, pos.y-4-tick, 10, 8);
//
//		
//		if (!weapon.twoHanded){
//			g.setColor(Color.red);
//			g.fillOval(pos.x, pos.y+10, 20, 3);
//			g.setColor(Color.black);
//			g.fillRect(pos.x+18, pos.y+10, 8, 2);
//			g.setColor(Color.red);
//			g.fillOval(pos.x, pos.y-13, 6+tick*2, 3);
//		} else {
//			g.rotate(pos.x, pos.y+10, -20);
//			g.setColor(Color.red);
//			g.fillOval(pos.x, pos.y+8, 20, 3);			
//			g.rotate(pos.x, pos.y+10,20);
//			
//			g.rotate(pos.x, pos.y-10, 30);
//			g.setColor(Color.red);
//			g.fillOval(pos.x, pos.y-12, 20, 3);			
//			g.rotate(pos.x, pos.y-10,-30);
//			
//			g.setColor(Color.black);
//			g.fillRect(pos.x+6, pos.y, 24, 2);

//		}
//		g.rotate(pos.x, pos.y, (float) -angle);

//		g.fillRect((float)(pos.x+shotPosition.x),(float) (pos.y+shotPosition.y), 2, 2);
	}

	@Override
	protected void onHit(GameObject damager) {
		playSound();
	}

	public boolean containsWeapon(int id){
		for(Weapon w : weapons)
			if (w.id == id)
				return true;
		return false;
	}
	
	public Weapon getWeapon(int id){
		for(Weapon w : weapons)
			if (w.id == id)
				return w;
		return null;
	}
	
	public void pickup(ItemObject itemObject) {
		pickup(itemObject.itemId);
		itemObject.remove();
	}
	
	private void pickup(int itemId) {
		pickup(Item.getItemById(itemId));
	}

	public void pickup(Item item) {
		if (item.type == ItemType.WEAPON){
			if (!containsWeapon(item.id)){
				weapons.add(Weapon.getWeaponById(item.id).clone());
				for(int i = 0; i < items.size();i++){
					Item it = items.get(i);
					if (it instanceof Ammo){
						if (((Ammo) it).weaponId == item.id){
							getWeapon(item.id).totalAmmo += it.count*((Ammo)it).ammo;
							items.remove(it);
						}
					}
				}
			} else
				getWeapon(item.id).totalAmmo += 
					Weapon.getWeaponById(item.id).maxAmmo;
		} else if (item.type == ItemType.AMMO){
			Ammo ammo = (Ammo) Item.items.get(item.id);
			if (!containsWeapon(ammo.weaponId)){
				if (containsItem(ammo.id))
					getItemById(ammo.id).count++;
				else
					items.add(ammo.clone());
			} else 
				getWeapon(ammo.weaponId).totalAmmo+=ammo.ammo;
		} else if (item.type == ItemType.HEAL){
			Heal heal =  (Heal) Item.items.get(item.id);
			if (containsItem(heal.id))
				getItemById(heal.id).count++;
			else
				items.add(heal.clone());
		} else if  (item.type == ItemType.EXPLOSION){
			Explosive exp = (Explosive) Item.items.get(item.id);
			if (containsItem(exp.id))
				getItemById(exp.id).count++;
			else
				items.add(exp.clone());
		}
	}	
	
	protected void doDie(GameObject damager, int value){
		super.doDie(damager,value);
		
//		BlurEffect blur = new BlurEffect();
//		blur.radius = 0.1f;
//		blur.radiusDelta = 0.005f;
//		blur.renderGroup = Constants.GROUP_LAST;
//
//		blur.setFullLifeTime(Long.MAX_VALUE);
//		
//		TextEffect eff = new TextEffect();
//		eff.text = "GAME OVER!";
//		eff.soundOn = false;
//		eff.color = Color.red;
//		eff.position = new Vector2f(Constants.SCREEN_WIDTH/2,Constants.SCREEN_HEIGHT/2);
//		eff.renderGroup = Constants.GROUP_LAST;
//		eff.setFullLifeTime(Long.MAX_VALUE);
//		GameState.addEffect(blur);
//		GameState.addEffect(eff);
//		ThreadPoolManager.getInstance().scheduleGeneral(new Runnable(){
//
//			@Override
//			public void run() {
//				if (GameState.player.isDead())
//					GameState.paused = true;	
//				
//			}}, 15000);
	}
	
	public Item getItemById(int id) {
		for( Item it : items)
			if (it.id == id)
				return it;
		return null;
	}

	public boolean containsItem(int id) {
		for( Item it : items)
			if (it.id == id)
				return true;
		return false;
	}

	public void use() {
		if (isDead())
			return;
		if (itemPosition == -1)
			return;
		
		Item it = items.get(itemPosition);
		if (it.type == ItemType.HEAL){
			if (getHp() == getMaxHp())
				return;
			setHp(getHp()+((Heal)it).heal);
			if (getHp() > getMaxHp())
				setHp(getMaxHp());
			it.count--;
		} else if (it.type == ItemType.EXPLOSION){
//			ExplosiveObject obj = new ExplosiveObject(pos.x,pos.y,(Explosive) it);
//			obj.angle = angle;
//			obj.owner = this;
//			GameState.addObject(obj);
//			it.count--;
		}
		
		if (it.count <= 0){
			items.remove(it);
			itemPosition = -1;
		}
		if (items.size() < itemPosition-1){
			itemPosition = -1;
		}
		
	}


}
